; This module is common to all of the examples.
; It services USB Requests from the SIE.
; Interpretation of the Output Reports is handled by MAIN
;
CSEG
ServiceSetupPacket:
MOV DPTR, #SETUPDAT ; Point to Setup Packet data
MOVX A, @DPTR ; Get the RequestType
MOV C, ACC.7 ; Bit 7 = 1 means IO device needs to send data to PC Host
MOV SendData, C
ANL A, #01011100b ; IF RequestType[6.4.3.2] = 1 THEN goto BadRequest
JNZ BadRequest
MOVX A, @DPTR ; IF RequestType[1&0] = 1 THEN goto BadRequest
MOV C, ACC.0
ANL C, ACC.1
JC BadRequest
JNB ACC.5, NotB5 ; IF RequestType[5] = 1 THEN RequestType[1,0] = [1,1]
MOV A, #00000011b
NotB5: ANL A, #00000011b ; Set CommandIndex[5,4] = RequestType[1,0]
SWAP A
MOV Temp, A ; Save HI nibble of CommandIndex
; Set CommandIndex[3,0] = Request[3,0]
INC DPTR ; Point to Request
MOVX A, @DPTR
ANL A, #00001111b ; Only 13 are defined today, handle in table
ORL A, Temp
CALL CorrectSubroutine ; goto CommandTable(CommandIndex)
; Returns STALL=1 if a stall is required
JB STALL, BadRequest
JNB SendData, HandShake
JB IsDescriptor, LoadSUDPTR; EZ-USB has a short cut for descriptors
; Send data in ReplyBuffer
MOV DPTR, #EP0InBuffer+2
MOV R0, #ReplyBuffer+3
MOV Temp, #3 ; Copy maximum byte count
CopyRB: MOV A, @R0
MOVX @DPTR, A
DEC DPL
DEC R0
DJNZ Temp, CopyRB
MOV A, @R0 ; Get real byte count
SendEP0InBuffer:
MOV DPTR, #In0ByteCount
StartXfer:
MOVX @DPTR, A ; This write initiates the transfer
HandShake: ; Handshake with host
MOV Temp, #00000010b ; Set HSNAK to tell the SIE that we're done
SetEP0Control:
MOV DPTR, #EP0Control
MOVX A, @DPTR
ORL A, Temp
MOVX @DPTR, A
RET
LoadSUDPTR: ; Send the data pointed to by DPTR
MOV Temp, DPL
MOV A, DPH
MOV DPTR, #SUDPTR
MOVX @DPTR, A
MOV A, Temp
INC DPTR
JMP StartXfer
BadRequest: ; Invalid Request was received
MOV Temp, #00000011b ; Set EP0STALL and HSNAK
JMP SetEP0Control
NextDPTR: ; Returns (DPTR + byte DPTR is pointing to)
MOVX A, @DPTR
BumpDPTR: ; Returns (DPTR + ACC)
ADD A, DPL
MOV DPL, A
JNC Skip
INC DPH ; Need 16 bit arithmetic here
Skip: RET
CorrectSubroutine: ; Jump to the subroutine that DPTR is pointing to
MOV DPTR, #CommandTable
CALL BumpDPTR ; Point to entry
MOVX A, @DPTR ; Get the offset
MOV DPTR, #CommandTable
CALL BumpDPTR ; Get the routine address
PUSH DPL ; Create a RETURN address on stack
PUSH DPH ; Note: JMP @A+DPTR not used since A, DPTR needed
MOV R0, #ReplyBuffer+2
CLR A
MOV @R0, A ; Clear ReplyBuffer
DEC R0
MOV @R0, A
DEC R0
MOV @R0, #1 ; Default non-descriptor reply
MOV DPTR, #SETUPDAT+2 ; Point to LOW(wValue)
MOVX A, @DPTR ; Many of the routines need these
MOV B, A ; LOW(wValue) in B
INC DPTR
MOVX A, @DPTR ; HIGH(wValue) in A
CLR STALL
CLR IsDescriptor
RET ; Go to service routine
; Since the table only contains byte offsets, it is important that all these routines are
; within one page (100H) of CommandTable
;
CommandTable:
; First 16 commands are for the Device
DB Device_Get_Status - CommandTable
DB Device_Clear_Feature - CommandTable
DB Invalid - CommandTable
DB Device_Set_Feature - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable ; SIE implements Device_Set_Address
DB Get_Descriptor - CommandTable
DB Set_Descriptor - CommandTable
DB Get_Configuration - CommandTable
DB Set_Configuration - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
; Next 16 commands are for the Interface
DB Interface_Get_Status - CommandTable
DB Interface_Clear_Feature - CommandTable
DB Invalid - CommandTable
DB Interface_Set_Feature - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Get_Class_Descriptor - CommandTable
DB Set_Class_Descriptor - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Get_Interface - CommandTable
DB Set_Interface - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
; Next 16 commands are for the Endpoint
DB Endpoint_Get_Status - CommandTable
DB Endpoint_Clear_Feature - CommandTable
DB Invalid - CommandTable
DB Endpoint_Set_Feature - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Endpoint_Sync_Frame - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
; Next 16 commands are Class Requests
DB Invalid - CommandTable
DB Get_Report - CommandTable
DB Get_Idle - CommandTable
DB Get_Protocol - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Set_Report - CommandTable
DB Set_Idle - CommandTable
DB Set_Protocol - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
DB Invalid - CommandTable
;
; Many requests are INVALID for this example
Get_Protocol: ; We are not a Boot device
Set_Protocol: ; We are not a Boot device
Set_Descriptor: ; Our Descriptors are static
Set_Class_Descriptor: ; Our Descriptors are static
Set_Interface: ; We only have one Interface
Get_Interface: ; We do not have an Alternate setting
Device_Set_Feature: ; We have no features that can be set or cleared
Interface_Set_Feature: ; We have no features that can be set or cleared
Endpoint_Set_Feature: ; We have no features that can be set or cleared
Device_Clear_Feature: ; We have no features that can be set or cleared
Interface_Clear_Feature: ; We have no features that can be set or cleared
Endpoint_Sync_Frame: ; We are not an Isonchronous device
Invalid: ; Invalid Request made, STALL the Endpoint
SETB STALL
;
Endpoint_Clear_Feature: ; We have no features that can be set or cleared
;
Reply: RET
Set_Report: ; Host wants to sent us a Report.
; The ONLY case in this example where host sends data to us
JNB Configured, Invalid ; Need to be Configured to do this command
MOV DPTR, #Out0ByteCount ; Enable EP0OutBuffer to receive data
MOVX @DPTR, A ; Any value will do
MOV DPTR, #OUT07IRQ ; Wait for valid data in EP0OutBuffer
Wait4D: MOVX A, @DPTR
ANL A, #00000001b
JZ Wait4D
MOVX @DPTR, A ; Clear the interrupt
JMP ProcessOutputReport ; RETurn via this subroutine
Get_Report: ; Host wants a Report
JNB Configured, Invalid ; Need to be Configured to do this command
INC R0 ; Point to ReplyBuffer(1)
MOV @R0, #18H ; Reply with a recognizable (arbitary) value
RET
Set_Idle: ; Host wants to tell us how often we should talk
JNB Configured, Invalid ; Need to be Configured to do this command
MOV Idle_Time, A
RET ; Handshake with host
Get_Idle: ; Host must have forgotten what he told us to do
JNB Configured, Invalid ; Need to be Configured to do this command
INC R0 ; Point to ReplyBuffer(1)
MOV @R0, Idle_Time
RET
Get_Configuration:
JNB Configured, Reply
; If configured return a 1 (via Device_Get_Status)
Device_Get_Status: ; Only two bits of Device Status are defined
INC R0 ; Point to ReplyBuffer(1)
MOV @R0, #1 ; Bit 1=Remote Wakeup(=0), Bit 0=Self Powered(=1)
RET
Interface_Get_Status: ; Interface Status is currently defined as 0
Endpoint_Get_Status:
MOV @R0, #2
RET
Set_Configuration: ; Valid values are 0 and 1
MOV A, B ; Get LOW(wValue)
JZ Deconfigured
DEC A
JNZ Invalid
SETB Configured
RET
Deconfigured:
CLR Configured
RET
Get_Descriptor: ; Host wants to know who/what we are
SETB IsDescriptor
DEC A ; Valid Values are 1, 2 and 3
MOV DPTR, #DeviceDescriptor
JZ Reply
DEC A
MOV DPTR, #ConfigurationDescriptor
JZ Reply
DEC A
JNZ Invalid
; Request is for a String Descriptor
MOV DPTR, #String0 ; Point to String 0
MOV A, B ; Get String Index
NextString:
JZ FixUpthenReply
MOV Temp, A ; Save String Index
CALL NextDPTR
MOVX A, @DPTR ; Get the String Length (= 0 means we're at Backstop)
JZ Invalid ; Asked for a string I don't have
MOV A, Temp
DEC A
JMP NextString ; Check if we are there yet
Get_Class_Descriptor: ; Valid values are 21H, 22H, 23H for Class Request
SETB IsDescriptor
CLR C
SUBB A, #21H
MOV DPTR, #HIDDescriptor
JZ Reply
DEC A
MOV DPTR, #ReportDescriptor
JZ Reply
; DEC A ; This example does not use Physical Descriptors
; JZ Send_Physical_Descriptor
JMP Invalid
;
; Error check: this MUST be on within a page of CommandTable
WithinSamePage EQU $ - CommandTable
;
FixUpthenReply: ; EZ-USB Rev D has a String Descriptor bug
; Need to fill the IN0BUF (@ 7F00H) myself
MOVX A, @DPTR ; Get the string length
MOV R7, A ; Save counter
MOV B, A
MOV R0, #LOW(EP0InBuffer) ; PageReg = 7FH = HIGH(EP0InBuffer)
CopySD: MOVX @R0, A
INC R0
INC DPTR
MOVX A, @DPTR
DJNZ R7, CopySD
; Fixup complete, get back to the program flow
POP ACC ; Get rid of the return address
POP ACC
MOV A, B ; Retrieve byte count
JMP SendEP0InBuffer